"""
保洁效率评估服务
实现保洁工作前后的对比分析，创建保洁效率的量化评估指标，开发保洁任务的智能调度建议
"""
import asyncio
import logging
import cv2
import numpy as np
from datetime import datetime, timedelta
from typing import List, Dict, Optional, Tuple, Any
from uuid import uuid4
import time
from collections import defaultdict, deque
import json

from schemas.hygiene_management import (
    CleaningTask, CleaningTaskStatus, CleaningTaskPriority,
    CleaningEfficiencyMetrics, CleanlinessAssessment, HygieneZone
)
from ai_services.campus_environment_hygiene.cleanliness_assessment_service import cleanliness_assessment_service
from ai_services.campus_environment_hygiene.waste_detection_service import waste_detection_service
from core.config import get_settings

logger = logging.getLogger(__name__)
settings = get_settings()


class EfficiencyCalculator:
    """效率计算器"""
    
    def calculate_cleaning_speed(self, area_cleaned: float, duration_minutes: int) -> float:
        """计算清洁速度（平方米/分钟）"""
        if duration_minutes <= 0:
            return 0.0
        return area_cleaned / duration_minutes
    
    def calculate_quality_improvement(self, before_score: float, after_score: float) -> float:
        """计算质量改善程度"""
        return max(0, after_score - before_score)
    
    def calculate_efficiency_rating(self, metrics: CleaningEfficiencyMetrics) -> str:
        """计算效率评级"""
        # 综合评分算法
        speed_score = min(metrics.cleaning_speed / 2.0, 1.0) * 25  # 速度评分（最高25分）
        quality_score = metrics.quality_score * 0.4  # 质量评分（最高40分）
        improvement_score = min(metrics.improvement_score / 20.0, 1.0) * 25  # 改善评分（最高25分）
        resolution_score = min(metrics.issues_resolved / 5.0, 1.0) * 10  # 问题解决评分（最高10分）
        
        total_score = speed_score + quality_score + improvement_score + resolution_score
        
        if total_score >= 90:
            return "excellent"
        elif total_score >= 80:
            return "good"
        elif total_score >= 70:
            return "fair"
        elif total_score >= 60:
            return "poor"
        else:
            return "very_poor"
    
    def calculate_productivity_index(self, metrics: CleaningEfficiencyMetrics) -> float:
        """计算生产力指数"""
        # 生产力指数 = (清洁面积 × 质量评分) / 时间
        if metrics.duration_minutes <= 0:
            return 0.0
        
        productivity = (metrics.area_cleaned * metrics.quality_score / 100) / metrics.duration_minutes
        return productivity


class TaskScheduler:
    """任务调度器"""
    
    def __init__(self):
        self.priority_weights = {
            CleaningTaskPriority.CRITICAL: 5.0,
            CleaningTaskPriority.URGENT: 4.0,
            CleaningTaskPriority.HIGH: 3.0,
            CleaningTaskPriority.MEDIUM: 2.0,
            CleaningTaskPriority.LOW: 1.0
        }
    
    def calculate_task_priority_score(self, task: CleaningTask, zone: HygieneZone) -> float:
        """计算任务优先级评分"""
        base_score = self.priority_weights.get(task.priority, 1.0)
        
        # 时间因子（创建时间越久优先级越高）
        age_hours = (datetime.now() - task.created_at).total_seconds() / 3600
        time_factor = min(age_hours / 24, 2.0)  # 最多2倍权重
        
        # 区域重要性因子
        zone_factor = 1.0
        if zone.zone_type == "restroom":
            zone_factor = 1.5
        elif zone.zone_type == "classroom":
            zone_factor = 1.2
        elif zone.zone_type == "hallway":
            zone_factor = 1.1
        
        # 清洁度差距因子
        cleanliness_gap = max(0, zone.cleanliness_standard - zone.current_cleanliness)
        gap_factor = 1.0 + (cleanliness_gap / 100)
        
        total_score = base_score * (1 + time_factor) * zone_factor * gap_factor
        
        return total_score
    
    def generate_cleaning_schedule(
        self, 
        tasks: List[CleaningTask], 
        zones: Dict[str, HygieneZone],
        available_cleaners: int = 3,
        time_horizon_hours: int = 8
    ) -> List[Dict[str, Any]]:
        """生成清洁调度计划"""
        # 过滤待处理的任务
        pending_tasks = [task for task in tasks if task.status == CleaningTaskStatus.PENDING]
        
        # 计算任务优先级评分
        task_scores = []
        for task in pending_tasks:
            zone = zones.get(task.zone_id)
            if zone:
                score = self.calculate_task_priority_score(task, zone)
                task_scores.append((task, score))
        
        # 按优先级排序
        task_scores.sort(key=lambda x: x[1], reverse=True)
        
        # 生成调度计划
        schedule = []
        current_time = datetime.now()
        cleaner_schedules = [[] for _ in range(available_cleaners)]
        cleaner_end_times = [current_time for _ in range(available_cleaners)]
        
        for task, score in task_scores:
            # 找到最早可用的清洁员
            earliest_cleaner = min(range(available_cleaners), key=lambda i: cleaner_end_times[i])
            
            # 计算开始时间
            start_time = max(current_time, cleaner_end_times[earliest_cleaner])
            
            # 估算结束时间
            estimated_duration = task.estimated_duration or 30  # 默认30分钟
            end_time = start_time + timedelta(minutes=estimated_duration)
            
            # 检查是否在时间范围内
            if (end_time - current_time).total_seconds() / 3600 <= time_horizon_hours:
                schedule_item = {
                    'task_id': task.task_id,
                    'task_title': task.title,
                    'zone_id': task.zone_id,
                    'priority': task.priority.value,
                    'priority_score': score,
                    'assigned_cleaner': f"cleaner_{earliest_cleaner + 1}",
                    'scheduled_start': start_time,
                    'scheduled_end': end_time,
                    'estimated_duration': estimated_duration
                }
                
                schedule.append(schedule_item)
                cleaner_schedules[earliest_cleaner].append(schedule_item)
                cleaner_end_times[earliest_cleaner] = end_time
        
        return schedule
    
    def optimize_cleaning_routes(self, tasks: List[CleaningTask], zones: Dict[str, HygieneZone]) -> List[str]:
        """优化清洁路线"""
        # 简化的路线优化：按区域类型和位置排序
        zone_priorities = {
            "restroom": 1,
            "kitchen": 2,
            "classroom": 3,
            "office": 4,
            "hallway": 5,
            "outdoor": 6
        }
        
        # 按区域优先级和位置排序任务
        sorted_tasks = sorted(tasks, key=lambda t: (
            zone_priorities.get(zones.get(t.zone_id, HygieneZone(zone_id="", zone_name="", zone_type="", coordinates=[], area_sqm=0, cleaning_frequency="", cleanliness_standard=0)).zone_type, 999),
            t.zone_id
        ))
        
        return [task.task_id for task in sorted_tasks]


class CleaningEfficiencyService:
    """保洁效率评估服务"""
    
    def __init__(self):
        self.efficiency_calculator = EfficiencyCalculator()
        self.task_scheduler = TaskScheduler()
        
        self.cleaning_tasks: Dict[str, CleaningTask] = {}
        self.efficiency_metrics: List[CleaningEfficiencyMetrics] = []
        self.cleaning_schedules: List[Dict[str, Any]] = []
        
        # 服务状态
        self._running = False
        self._monitoring_task = None
        self.monitoring_interval = 60.0  # 1分钟检查一次
        
        # 统计信息
        self.stats = {
            'total_tasks': 0,
            'completed_tasks': 0,
            'average_efficiency_rating': 'fair',
            'average_cleaning_speed': 0.0,
            'average_quality_improvement': 0.0,
            'cleaner_performance': {}
        }
    
    async def start_service(self):
        """启动服务"""
        if self._running:
            return
        
        self._running = True
        self._monitoring_task = asyncio.create_task(self._monitoring_loop())
        logger.info("Cleaning efficiency service started")
    
    async def stop_service(self):
        """停止服务"""
        self._running = False
        if self._monitoring_task:
            self._monitoring_task.cancel()
            try:
                await self._monitoring_task
            except asyncio.CancelledError:
                pass
        logger.info("Cleaning efficiency service stopped")
    
    async def _monitoring_loop(self):
        """监控循环"""
        while self._running:
            try:
                await self._periodic_monitoring()
                await asyncio.sleep(self.monitoring_interval)
            except asyncio.CancelledError:
                break
            except Exception as e:
                logger.error(f"Error in cleaning efficiency monitoring loop: {e}")
                await asyncio.sleep(30.0)
    
    async def _periodic_monitoring(self):
        """周期性监控"""
        # 检查超时的任务
        current_time = datetime.now()
        
        for task in self.cleaning_tasks.values():
            if (task.status == CleaningTaskStatus.IN_PROGRESS and 
                task.started_at and 
                task.estimated_duration):
                
                expected_end = task.started_at + timedelta(minutes=task.estimated_duration)
                if current_time > expected_end + timedelta(minutes=30):  # 超时30分钟
                    logger.warning(f"Task {task.task_id} is overdue")
        
        # 清理过期数据
        cutoff_time = current_time - timedelta(days=30)
        self.efficiency_metrics = [
            metric for metric in self.efficiency_metrics
            if metric.start_time > cutoff_time
        ]
        
        # 更新统计信息
        self._update_statistics()
    
    def _update_statistics(self):
        """更新统计信息"""
        completed_tasks = [task for task in self.cleaning_tasks.values() if task.status == CleaningTaskStatus.COMPLETED]
        
        self.stats['total_tasks'] = len(self.cleaning_tasks)
        self.stats['completed_tasks'] = len(completed_tasks)
        
        if self.efficiency_metrics:
            # 计算平均清洁速度
            speeds = [m.cleaning_speed for m in self.efficiency_metrics]
            self.stats['average_cleaning_speed'] = sum(speeds) / len(speeds)
            
            # 计算平均质量改善
            improvements = [m.improvement_score for m in self.efficiency_metrics]
            self.stats['average_quality_improvement'] = sum(improvements) / len(improvements)
            
            # 计算平均效率评级
            ratings = [m.efficiency_rating for m in self.efficiency_metrics]
            rating_scores = {
                'excellent': 5, 'good': 4, 'fair': 3, 'poor': 2, 'very_poor': 1
            }
            avg_score = sum(rating_scores.get(r, 3) for r in ratings) / len(ratings)
            
            if avg_score >= 4.5:
                self.stats['average_efficiency_rating'] = 'excellent'
            elif avg_score >= 3.5:
                self.stats['average_efficiency_rating'] = 'good'
            elif avg_score >= 2.5:
                self.stats['average_efficiency_rating'] = 'fair'
            elif avg_score >= 1.5:
                self.stats['average_efficiency_rating'] = 'poor'
            else:
                self.stats['average_efficiency_rating'] = 'very_poor'
            
            # 计算清洁员绩效
            cleaner_metrics = defaultdict(list)
            for metric in self.efficiency_metrics:
                if metric.cleaner_id:
                    cleaner_metrics[metric.cleaner_id].append(metric)
            
            self.stats['cleaner_performance'] = {}
            for cleaner_id, metrics in cleaner_metrics.items():
                avg_speed = sum(m.cleaning_speed for m in metrics) / len(metrics)
                avg_quality = sum(m.quality_score for m in metrics) / len(metrics)
                avg_improvement = sum(m.improvement_score for m in metrics) / len(metrics)
                
                self.stats['cleaner_performance'][cleaner_id] = {
                    'task_count': len(metrics),
                    'average_speed': avg_speed,
                    'average_quality': avg_quality,
                    'average_improvement': avg_improvement,
                    'efficiency_rating': self.efficiency_calculator.calculate_efficiency_rating(metrics[0]) if metrics else 'unknown'
                }
    
    async def create_cleaning_task(
        self,
        title: str,
        description: str,
        zone_id: str,
        camera_id: str,
        priority: CleaningTaskPriority = CleaningTaskPriority.MEDIUM,
        estimated_duration: Optional[int] = None,
        related_issues: List[str] = None
    ) -> CleaningTask:
        """创建清洁任务"""
        task = CleaningTask(
            task_id=str(uuid4()),
            task_type="manual_created",
            title=title,
            description=description,
            priority=priority,
            status=CleaningTaskStatus.PENDING,
            zone_id=zone_id,
            camera_id=camera_id,
            related_issues=related_issues or [],
            estimated_duration=estimated_duration,
            created_at=datetime.now()
        )
        
        self.cleaning_tasks[task.task_id] = task
        logger.info(f"Created cleaning task: {task.task_id}")
        
        return task
    
    async def start_cleaning_task(self, task_id: str, cleaner_id: str) -> bool:
        """开始清洁任务"""
        if task_id not in self.cleaning_tasks:
            return False
        
        task = self.cleaning_tasks[task_id]
        
        if task.status != CleaningTaskStatus.PENDING:
            return False
        
        task.status = CleaningTaskStatus.IN_PROGRESS
        task.assigned_to = cleaner_id
        task.assigned_at = datetime.now()
        task.started_at = datetime.now()
        
        logger.info(f"Started cleaning task {task_id} by cleaner {cleaner_id}")
        return True
    
    async def complete_cleaning_task(
        self,
        task_id: str,
        before_image: Optional[np.ndarray] = None,
        after_image: Optional[np.ndarray] = None,
        tools_used: List[str] = None,
        notes: str = ""
    ) -> Optional[CleaningEfficiencyMetrics]:
        """完成清洁任务并评估效率"""
        if task_id not in self.cleaning_tasks:
            return None
        
        task = self.cleaning_tasks[task_id]
        
        if task.status != CleaningTaskStatus.IN_PROGRESS:
            return None
        
        task.status = CleaningTaskStatus.COMPLETED
        task.completed_at = datetime.now()
        task.notes = notes
        
        # 计算实际持续时间
        if task.started_at:
            actual_duration = int((task.completed_at - task.started_at).total_seconds() / 60)
            task.actual_duration = actual_duration
        else:
            actual_duration = task.estimated_duration or 30
        
        # 评估清洁效率
        metrics = await self._evaluate_cleaning_efficiency(task, before_image, after_image, tools_used)
        
        if metrics:
            self.efficiency_metrics.append(metrics)
            
            # 保持最近1000个指标
            if len(self.efficiency_metrics) > 1000:
                self.efficiency_metrics = self.efficiency_metrics[-1000:]
        
        logger.info(f"Completed cleaning task {task_id}")
        return metrics
    
    async def _evaluate_cleaning_efficiency(
        self,
        task: CleaningTask,
        before_image: Optional[np.ndarray],
        after_image: Optional[np.ndarray],
        tools_used: List[str] = None
    ) -> Optional[CleaningEfficiencyMetrics]:
        """评估清洁效率"""
        try:
            # 获取区域信息
            zone = cleanliness_assessment_service.get_zone(task.zone_id)
            if not zone:
                logger.warning(f"Zone {task.zone_id} not found")
                return None
            
            area_cleaned = zone.area_sqm
            duration_minutes = task.actual_duration or task.estimated_duration or 30
            
            # 计算清洁速度
            cleaning_speed = self.efficiency_calculator.calculate_cleaning_speed(area_cleaned, duration_minutes)
            
            # 评估清洁质量
            before_score = 60.0  # 默认清洁前评分
            after_score = 85.0   # 默认清洁后评分
            
            if before_image is not None and after_image is not None:
                # 使用图像分析评估清洁效果
                before_assessment = await cleanliness_assessment_service.assess_image_cleanliness(
                    before_image, task.camera_id, task.zone_id
                )
                after_assessment = await cleanliness_assessment_service.assess_image_cleanliness(
                    after_image, task.camera_id, task.zone_id
                )
                
                before_score = before_assessment.cleanliness_score
                after_score = after_assessment.cleanliness_score
            
            # 计算改善评分
            improvement_score = self.efficiency_calculator.calculate_quality_improvement(before_score, after_score)
            
            # 计算解决的问题数量
            issues_resolved = len(task.related_issues)
            
            # 创建效率指标
            metrics = CleaningEfficiencyMetrics(
                metrics_id=str(uuid4()),
                cleaner_id=task.assigned_to,
                zone_id=task.zone_id,
                task_id=task.task_id,
                start_time=task.started_at or task.created_at,
                end_time=task.completed_at,
                duration_minutes=duration_minutes,
                area_cleaned=area_cleaned,
                cleaning_speed=cleaning_speed,
                quality_score=after_score,
                before_cleanliness_score=before_score,
                after_cleanliness_score=after_score,
                improvement_score=improvement_score,
                efficiency_rating="",  # 将在下面计算
                issues_resolved=issues_resolved,
                tools_used=tools_used or []
            )
            
            # 计算效率评级
            metrics.efficiency_rating = self.efficiency_calculator.calculate_efficiency_rating(metrics)
            
            return metrics
            
        except Exception as e:
            logger.error(f"Failed to evaluate cleaning efficiency: {e}")
            return None
    
    async def generate_cleaning_schedule(
        self,
        available_cleaners: int = 3,
        time_horizon_hours: int = 8
    ) -> List[Dict[str, Any]]:
        """生成清洁调度计划"""
        try:
            # 获取待处理的任务
            pending_tasks = [task for task in self.cleaning_tasks.values() if task.status == CleaningTaskStatus.PENDING]
            
            # 获取区域信息
            zones = {zone.zone_id: zone for zone in cleanliness_assessment_service.get_zones()}
            
            # 生成调度计划
            schedule = self.task_scheduler.generate_cleaning_schedule(
                pending_tasks, zones, available_cleaners, time_horizon_hours
            )
            
            # 存储调度计划
            schedule_record = {
                'schedule_id': str(uuid4()),
                'generated_at': datetime.now(),
                'time_horizon_hours': time_horizon_hours,
                'available_cleaners': available_cleaners,
                'total_tasks': len(schedule),
                'schedule': schedule
            }
            
            self.cleaning_schedules.append(schedule_record)
            
            # 保持最近50个调度计划
            if len(self.cleaning_schedules) > 50:
                self.cleaning_schedules = self.cleaning_schedules[-50:]
            
            return schedule
            
        except Exception as e:
            logger.error(f"Failed to generate cleaning schedule: {e}")
            return []
    
    async def get_cleaning_recommendations(self, zone_id: str) -> List[str]:
        """获取清洁建议"""
        recommendations = []
        
        try:
            # 获取区域信息
            zone = cleanliness_assessment_service.get_zone(zone_id)
            if not zone:
                return recommendations
            
            # 获取最近的评估结果
            recent_assessments = await cleanliness_assessment_service.get_assessments(
                zone_id=zone_id,
                limit=5
            )
            
            if recent_assessments:
                latest_assessment = recent_assessments[0]
                
                # 基于清洁度评分给出建议
                if latest_assessment.cleanliness_score < zone.cleanliness_standard:
                    gap = zone.cleanliness_standard - latest_assessment.cleanliness_score
                    
                    if gap > 20:
                        recommendations.append("需要深度清洁，建议安排专业清洁团队")
                    elif gap > 10:
                        recommendations.append("需要加强清洁，建议增加清洁频率")
                    else:
                        recommendations.append("需要常规清洁维护")
                
                # 基于检测到的问题给出建议
                for issue in latest_assessment.detected_issues:
                    if issue['type'] == 'waste':
                        recommendations.append(f"发现{issue['waste_type']}垃圾，需要及时清理")
                
                # 基于评估因子给出具体建议
                factors = latest_assessment.assessment_factors
                
                if factors.get('waste_presence', 100) < 70:
                    recommendations.append("垃圾较多，建议增加垃圾桶并提高清理频率")
                
                if factors.get('surface_cleanliness', 100) < 70:
                    recommendations.append("表面清洁度不足，建议使用专业清洁剂进行深度清洁")
                
                if factors.get('organization', 100) < 70:
                    recommendations.append("物品摆放凌乱，建议整理并制定摆放标准")
            
            # 基于历史效率数据给出建议
            zone_metrics = [m for m in self.efficiency_metrics if m.zone_id == zone_id]
            
            if zone_metrics:
                avg_speed = sum(m.cleaning_speed for m in zone_metrics) / len(zone_metrics)
                
                if avg_speed < 1.0:  # 清洁速度较慢
                    recommendations.append("清洁效率较低，建议优化清洁流程和工具配置")
                
                avg_improvement = sum(m.improvement_score for m in zone_metrics) / len(zone_metrics)
                
                if avg_improvement < 10:  # 改善效果不明显
                    recommendations.append("清洁效果改善不明显，建议检查清洁方法和标准")
            
            # 基于区域类型给出专门建议
            if zone.zone_type == "restroom":
                recommendations.append("洗手间需要特别注意消毒和除臭")
            elif zone.zone_type == "kitchen":
                recommendations.append("厨房需要重点清洁油污和食物残渣")
            elif zone.zone_type == "classroom":
                recommendations.append("教室需要注意桌椅整理和黑板清洁")
            
        except Exception as e:
            logger.error(f"Failed to get cleaning recommendations: {e}")
        
        return recommendations
    
    async def get_cleaning_tasks(
        self,
        status: Optional[CleaningTaskStatus] = None,
        zone_id: Optional[str] = None,
        assigned_to: Optional[str] = None,
        priority: Optional[CleaningTaskPriority] = None,
        limit: int = 100
    ) -> List[CleaningTask]:
        """获取清洁任务"""
        tasks = list(self.cleaning_tasks.values())
        
        # 过滤条件
        if status:
            tasks = [t for t in tasks if t.status == status]
        
        if zone_id:
            tasks = [t for t in tasks if t.zone_id == zone_id]
        
        if assigned_to:
            tasks = [t for t in tasks if t.assigned_to == assigned_to]
        
        if priority:
            tasks = [t for t in tasks if t.priority == priority]
        
        # 按创建时间倒序排列
        tasks.sort(key=lambda x: x.created_at, reverse=True)
        
        return tasks[:limit]
    
    async def get_efficiency_metrics(
        self,
        cleaner_id: Optional[str] = None,
        zone_id: Optional[str] = None,
        start_time: Optional[datetime] = None,
        end_time: Optional[datetime] = None,
        limit: int = 100
    ) -> List[CleaningEfficiencyMetrics]:
        """获取效率指标"""
        metrics = self.efficiency_metrics
        
        # 过滤条件
        if cleaner_id:
            metrics = [m for m in metrics if m.cleaner_id == cleaner_id]
        
        if zone_id:
            metrics = [m for m in metrics if m.zone_id == zone_id]
        
        if start_time:
            metrics = [m for m in metrics if m.start_time >= start_time]
        
        if end_time:
            metrics = [m for m in metrics if m.start_time <= end_time]
        
        # 按开始时间倒序排列
        metrics.sort(key=lambda x: x.start_time, reverse=True)
        
        return metrics[:limit]
    
    def get_statistics(self) -> Dict[str, Any]:
        """获取统计信息"""
        return self.stats.copy()
    
    def get_cleaning_schedules(self, limit: int = 10) -> List[Dict[str, Any]]:
        """获取清洁调度计划"""
        return sorted(self.cleaning_schedules, key=lambda x: x['generated_at'], reverse=True)[:limit]


# 全局保洁效率评估服务实例
cleaning_efficiency_service = CleaningEfficiencyService()